﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using KinectDwa.InputDevices;

namespace KinectDwa.Parsers
{
    public enum GestureType
    {
        None,
        Push,
        HandGesture /*,
        //DraggingMouse, // Update on HandGesture
        //HandOpenClose
        */
    }

    public static class MouseInputControl
    {
        #region Private settings
        #region Input settings

        // Defines if mouse events are generated
        private static bool _disableMouse = false; // false
        public static bool disableMouse { get { return _disableMouse; } }

        // Prevent clicks even though mouse could be active
        private static bool _disableClicks = true; // false
        public static bool disableClicks { get { return _disableClicks; } }

        // Toggles mode where moving the mouse requires pointing gesture, could be set by the software during use
        // Remembers old mouse positions and is therefore slower and more accurate
        private static bool _mouseDragging = false; // false
        public static bool mouseDragging { get { return _mouseDragging; } }

        // Pushbutton settings, true to replace hand gestures with limp wristed slapping
        private static bool _pushGestures = false; // false
        public static bool pushGestures { get { return _pushGestures; } }

        // Secondary gestures are alternative, more sign-like gestures used in twohanded controls
        private static bool _alternativeGestures = false; // false
        public static bool alternativeGestures { get { return _alternativeGestures; } }

        // Use secondary hand to do gestures and pointing hand to aim mouse
        private static bool _dualWield = false; // false
        public static bool dualWield { get { return _dualWield; } }

        // Forces hand usage, if null hand is picked automatically, if false its left
        private static bool? _handRight = true; // null
        public static bool? handRight { get { return _handRight; } }

        // Defines wether gestures can be performed in any angle
        private static bool _gestureRotation = true; // true
        public static bool gestureRotation { get { return _gestureRotation; } }

        // Changeable gesture accuracy
        private static float _requiredGestureAccuracy = requiredDefaultGestureAccuracy;
        public static float requiredGestureAccuracy { get { return _requiredGestureAccuracy; } }

        #endregion
        #region Constant tweaking values
        // MouseCenter is moved further from shoulder
        public const float shoulderAdjustX = 0.20F;
        public const float shoulderAdjustY = -0.03F;

        // Simple softening applied to the mouse but not to the skeleton
        public const int mouseSofteningMemoryCount = 3;

        // Distance hand needs to be extended to consider pointing started / ended
        // Might need to be based on user´s size
        public const float loseMouseControlTreshold = -100F; // 0.2F
        public const float gainMouseControlTreshold = 0.4F; // 0.4F

        // Soften shoulder location to a nice average, frames of previous shoulder depth locations memorized
        public const int shoulderMemoryFrames = 30; // 30, don't set to 0

        // Gesture has to match data this well to count, values 1F - 0F
        public const float requiredDefaultGestureAccuracy = 0.83F; // 0.80F old, 0.83F 
        public const float requiredAlternativeGestureAccuracy = 0.75F; // 0.75F

        // Remember x amount of previous gesture data and pick the most prevalent one
        public const int gestureMemoryCount = 10; // 10 default when on, 1 to turn "off"

        // Mouse coordinates, probably fine as they are
        private static double _mouseCenterX = System.Windows.SystemParameters.PrimaryScreenWidth / 2; //320.0F;
        public static double mouseCenterX { get { return _mouseCenterX; } }
        private static double _mouseCenterY = System.Windows.SystemParameters.PrimaryScreenHeight / 2;//240.0F;
        public static double mouseCenterY { get { return _mouseCenterY; } }

        // Mouse sensitivity for normal mouse
        public const float normalMouseSensitivity = 2250.0F; // 2500.0F

        // Mouse sensitivity for dragging
        public const float draggingMouseSensitivity = 2000.0F; // 2000.0F
                
        // Distance (depthValue) moved during PushDuration to activate click gesture
        public const int pushTreshold = 85; // 90, 100-250
        public const int OneHandedPushTreshold = 65; // 90, 100-250

        // Decay speed for push gestures
        public const int decaySpeed = 9; // 5 - 15
        public const int OneHandedDecaySpeed = 6; // 5 - 15
        
        // Do not immediately release clicks, sets frame delay when click is released
        public const int clickPersistency = 5; // 5

        // Do not immediately accept new clicks, sets frame delay when click is accepted
        public const int clickCoolDown = 5; // 5

        #endregion
        #endregion

        public static void EnableMouse()
        {
            _disableMouse = false;
        }

        public static void DisableMouse()
        {
            _disableMouse = true;
        }

        public static void EnableGestureRotation()
        {
            _gestureRotation = true;
        }

        public static void DisableGestureRotation()
        {
            _gestureRotation = false;
        }

        public static void SetHand(bool? rightHand)
        {
            _handRight = rightHand;
        }

        public static void SetInputType(GestureType newInputType, bool twoHanded)
        {
            if (newInputType == GestureType.None)
            {
                _mouseDragging = false;
                _pushGestures = false;
                _disableClicks = true;
                _alternativeGestures = false;
                _gestureRotation = false;
            }
            else if (newInputType == GestureType.Push)
            {
                _mouseDragging = false;
                _pushGestures = true;
                _disableClicks = false;
                _alternativeGestures = false;
                _gestureRotation = false;
            }
            else if (newInputType == GestureType.HandGesture)
            {
                _mouseDragging = false;
                _pushGestures = false;
                _disableClicks = false;

                //if (twoHanded)
                //{
                //    _alternativeGestures = true;
                //    _requiredGestureAccuracy = requiredAlternativeGestureAccuracy;
                //    _gestureRotation = true; // false!
                //}
                //else
                //{
                    _alternativeGestures = false;
                    _requiredGestureAccuracy = requiredDefaultGestureAccuracy;
                    _gestureRotation = true;
               // }
            }
            // TODO: currently not up to date so recheck values if adding back
            /*
            else if (newInputType == GestureType.DraggingMouse)
            {
                _mouseDragging = true;
                _pushGestures = false;
                _disableClicks = false;
                _alternativeGestures = false;
            }
            else if (newInputType == GestureType.HandOpenClose)
            {
                _mouseDragging = false;
                _pushGestures = false;
                _disableClicks = false;
                _alternativeGestures = true;
            }
             */

            _dualWield = twoHanded;
        }
    }
}
